import json
from datetime import datetime
from decimal import Decimal
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import JsonResponse
from django.utils import timezone
from django.views import View
from django_redis import get_redis_connection
from apps.goods.models import SKU
from apps.orders.models import OrderInfo, OrderGoods
from apps.users.models import Address

#事务
from django.db import transaction
# Create your views here.

class OrderSettlementView(LoginRequiredMixin, View):
    def get(self,request):
        # 1.先获取用户信息
        user = request.user
        #2.再获取地址信息
        addresses = Address.objects.filter(user=user,is_deleted=False)
        # 补充运费
        freight = Decimal(10.00)
        #定义一个空字典
        address_list = []
        # 把数据循环遍历，转换为字典，返回给前端
        for address in addresses:
            address_list.append({
                'id':address.id,
                'province':address.province.name,
                'city':address.city.name,
                'district':address.district.name,
                'place':address.place,
                'receiver':address.receiver,
                'mobile':address.mobile
            })
        # 这是从redis获取数据第一种转换方法
        # 从redis_cilent获取数据
        # redis_conn = get_redis_connection('carts')
        # redis_cart = redis_conn.hgetall('carts_%s' % user.id)
        # cart_selected = redis_conn.smembers('selected_%s' % user.id)
        # cart = {}
        # for sku_id in cart_selected:
        #     cart[int(sku_id)] = int(redis_cart[sku_id])
        # #查询商品信息
        # sku_list = []
        # # 查询商品信息
        # skus = SKU.objects.filter(id__in=cart.keys())
        # for sku in skus:
        #     sku_list.append({
        #         'id':sku.id,
        #         'name':sku.name,
        #         'default_image_url':sku.default_image.url,
        #         'count': cart[sku.id],
        #         'price':sku.price
        #     })
        # 这是第二种
        redis_data = get_redis_connection('carts')
        redis_cart = redis_data.hgetall('carts_%s' % user.id)
        new_dict = {}
        for sku_id,count in redis_cart.items():
            new_dict[int(sku_id)] = int(count)
        selected_ids  = redis_data.smembers('selected_%s' % user.id)
        new_list = []
        for id in selected_ids:
            new_list.append(int(id))
        cart_data = []
        skus = SKU.objects.filter(id__in=new_list)
        for sku in skus:
            cart_data.append({
                'id':sku.id,
                'name':sku.name,
                'default_image_url':sku.default_image.url,
                'count': new_dict[sku.id],
                'price':sku.price
            })
        # 定义一个返回前端需要返回的数据，，，，返回给前端的数据必须要跟前端需要字段一致
        context = {
            'addresses': address_list,
            'skus': cart_data,
            'freight': freight,
        }
        # 返回响应
        return JsonResponse({'code':0,'errmsg':'ok','context':context})

















class OrderCommitViews(LoginRequiredMixin,View):
    def post(self,request):
        # 接收参数，获取用户信息
        user= request.user
        json_data = json.loads(request.body.decode())
        # 获取前端的地址参数
        address_id = json_data.get('address_id')
        # 获取前端的支付信息的参数
        pay_method = json_data.get('pay_method')
        # 校验参数
        if not all((address_id,pay_method)):
            return JsonResponse({'code':400,'errmsg':'参数不全'})
        # 获取需要的地址
        try:
            addresses =Address.objects.get(id=address_id,user=user)
        except:
            return JsonResponse({'code':400,'errmsg':'地址信息错误'})
        # 判断支付信息是否有误
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'],OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
                return JsonResponse({'code':400,'errmsg':'支付信息错误'})
        # 判断支付状态
        status = 0
        if pay_method is OrderInfo.PAY_METHODS_ENUM['CASH']:
            status = OrderInfo.ORDER_STATUS_ENUM['UNPAID']
        else:
            status =OrderInfo.ORDER_STATUS_ENUM['UNSEND']
        # 生成订单单号

        order_id = datetime.now().strftime('%Y%m%d%H%M%f') + '%09d' % user.id
        # 开始事务
        # 事务的开始点
        with transaction.atomic():
            start_point = transaction.savepoint()
            try:
                # 进行存储数据
                orderinfo = OrderInfo.objects.create(
                    order_id= order_id,
                    user= request.user,
                    address=addresses,
                    total_count=0,
                    total_amount=Decimal('0'),
                    freight = Decimal('10.0')
                )
                # 从redisl库里面拿取商品数据
                # 连接redis
                redis_data = get_redis_connection('carts')
                redis_cart = redis_data.hgetall('carts_%s' % user.id)
                new_dict  = {}
                for sku_ids,count in redis_cart.items():
                    new_dict[int(sku_ids)]  =int(count)
                redis_selected = redis_data.smembers('selected_%s' % user.id)
                new_list = []
                for id in redis_selected:
                    new_list.append(int(id))
                for id in new_list:
                    sku = SKU.objects.get(id=id)
                    count = new_dict.get(id)
                    # 判断库存是否充足
                    if sku.stock < count:
                        # 如果库存不充足就回滚
                        transaction.savepoint_rollback(start_point)
                        return JsonResponse({'code':400,'errmsg':'库存不足'})
                    # 进行乐观锁的操作
                    old_stock = sku.stock
                    new_stock = old_stock -count
                    new_sales = new_stock + count
                    result = SKU.objects.filter(id=id,stock=old_stock).update(stock=new_stock,sales=new_sales)
                    if result:
                        print('下单成功')
                    else:
                        return JsonResponse({'code':400,'errmsg':'-------下单失败'})
                    # 然后进行保存到数据库里面
                    OrderGoods.objects.create(
                        order = orderinfo,
                        sku=sku,
                        count = count,
                        price = sku.price

                    )
                    # 进行计算商品总数量和商品总价格
                    orderinfo.total_count+=count
                    orderinfo.total_amount+=(count *sku.price)
                orderinfo.total_amount = orderinfo.total_amount+orderinfo.freight
                orderinfo.save()
            # 触发异常，事务开始回滚
            except:
                transaction.savepoint_rollback(start_point)
            # 否则的话就提交事务
            else:
                transaction.savepoint_commit(start_point)
        # 进行订单删除操作
        pl = redis_data.pipeline()
        pl.hdel('carts_%s' % user.id,*redis_selected)
        pl.srem('selected_%s' % user.id,*redis_selected)
        # 执行管道
        pl.execute()
        # 返回订单id给前端
        return JsonResponse({'code':0,'errmsg':'ok','order_id':order_id})






